package com.apes.fn.scm.retailOrder.service.retailProcess.process;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderDiscount;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.model.RetailOrderPayMethod;
import com.apes.fn.scm.retailOrder.repository.RetailOrderPayMethodRepository;
import com.apes.fn.scm.retailOrder.service.retailProcess.ServerAndLossQuotationProcess;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.soe.store.database.repository.SceneRepository;
import com.apes.scm.masterdata.finance.model.CrossIC;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 服务单
 * <p>
 * 如果是存在异业合作，就执行异业场景流
 *
 * @author wuq
 * @create 2021-05-21 16:55
 */
@Service
public class ServicePlanProcess extends ServerAndLossQuotationProcess {

    @Override
    public void beforeSave(RetailOrder retailOrder) {
        beforeProcess(retailOrder, this::addServiceDept);

        // 异业处理
        crossIC(retailOrder);

        // 增加 单位客户挂账判断，走异业的逻辑，但是不走异业的账目
        unitClient(retailOrder);
    }

    /**
     * 判断是否为异业， 赋值场景流  RO004
     *
     * @param retailOrder RetailOrder
     */
    private void crossIC(RetailOrder retailOrder) {
        // 遍历折扣明细，如果是异业合作的就去掉场景流
        List<Map<CrossIC, List<RetailOrderDiscount>>> groupMaps = retailOrder.getSaleItems().stream()
                .filter(retailOrderItem -> retailOrderItem.getRetailDiscounts().size() > 0)
                .map(retailOrderItem -> retailOrderItem.getRetailDiscounts().stream()
                        .filter(RetailOrderDiscount::checkIsCrossIC)
                        .collect(Collectors.groupingBy(RetailOrderDiscount::getCrossIC)))
                .collect(Collectors.toList());
        long count = groupMaps.stream().filter(crossICListMap -> !crossICListMap.isEmpty()).count();
        if (count > 0) {
            retailOrder.setScene(SpringManager.getBean(SceneRepository.class).findOne("RO004"));
        }
    }

    /**
     * 单位客户处理，单位客户走异业的流程，但是不走异业的账目
     *
     * @param retailOrder RetailOrder
     */
    private void unitClient(RetailOrder retailOrder) {
        ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(retailOrder.getSource());
        List<ServicePlanItem> unitClientPlanItems = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> Objects.nonNull(servicePlanItem.getUnitClient()))
                .collect(Collectors.toList());
        if (unitClientPlanItems.size() == 0) return;

        retailOrder.setScene(SpringManager.getBean(SceneRepository.class).findOne("RO004"));
    }

    private void addServiceDept(RetailOrder retailOrder) {
        retailOrder.setSourceBusinessType(ServicePlan.class.getSimpleName());

        if (!StringUtils.isEmpty(retailOrder.getSource())) {
            // 通过主表取服务门店
            String[] string = retailOrder.getSource().split(";");
            String planId = string[0];
            ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(planId);
            retailOrder.setServiceDept(servicePlan.getServiceDept()); // 服务门店编码
            retailOrder.setInsuranceDiscounts(servicePlan.getInsuranceDiscounts());   // e 保养服务
        } else {
            // 通过明细取服务门店
            RetailOrderItem orderItem = retailOrder.getSaleItems().stream()
                    .filter(retailOrderItem -> !StringUtils.isEmpty(retailOrderItem.getOriginnumber()))
                    .findFirst().orElse(null);
            ServicePlanItem servicePlanItem = SpringManager.getBean(ServicePlanItemRepository.class).findOne(orderItem.getOriginnumber());
            retailOrder.setServiceDept(servicePlanItem.getServicePlan().getServiceDept());  // 工单内协这里无法区分
            retailOrder.setInsuranceDiscounts(servicePlanItem.getServicePlan().getInsuranceDiscounts());
        }

        updateItem(retailOrder);
    }

    @Override
    public void afterSave(RetailOrder retailOrder) {
        // 单位客户检查
        checkUnitClient(retailOrder);

        // 回调方案完成状态
        callbackServicePlanFinished(retailOrder);

        // 自动归还与减可用数
        updateProductAvailable(retailOrder);
    }

    private void checkUnitClient(RetailOrder retailOrder) {
        ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(retailOrder.getSource());
        List<ServicePlanItem> unitClientPlanItems = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> Objects.nonNull(servicePlanItem.getUnitClient()))
                .collect(Collectors.toList());
        if (unitClientPlanItems.size() == 0) return;

        // 单位客户额挂账，只能有一条其他应收的记录
        long count = retailOrder.getPaymentMethodSet().stream().filter(payMethod -> "09".equals(payMethod.getPaymentMethodType().getId())).count();
        if (count == 0 || count > 1) {
            throw new RuntimeException("该来源的服务方案是单位客户挂账的单据，零售收款方式上面必须含有或者只能含有一条其他应收的记录");
        }

        // 获取其他应收的挂账金额，为了避免报错，先 filter
        final double paymentAmt = retailOrder.getPaymentMethodSet().stream()
                .filter(payMethod -> "09".equals(payMethod.getPaymentMethodType().getId()))
                .mapToDouble(RetailOrderPayMethod::getAmount).sum();

        // 根据单位客户分组，检查挂账金额
        unitClientPlanItems.stream().collect(Collectors.groupingBy(ServicePlanItem::getUnitClient))
                .forEach((unitClient, planItems) -> {
                    double planItemAmt = planItems.stream().mapToDouble(ServicePlanItem::getPftPriceUnit).sum();

                    //  检查挂账金额是否一致: 由于 APP 控制只能有一个挂账客户，这里直接比较
                    if (planItemAmt != paymentAmt) {
                        throw new RuntimeException("该来源的服务方案是单位客户挂账的单据，零售单中的挂账金额与服务方案上面的金额不一致");
                    }

                });
    }


    @Override
    public boolean support(String orderType) {
        return "server".equals(orderType);
    }
}
